using System;
using System.Collections;
using System.IO;
using System.Resources;
using Gtk;
using MonoDevelop.ResourceEditor;

namespace MonoDevelop.ResourceEditor.Gui
{
	/// <summary>Defines the properties and methods for the ResourceEditorView widget.</summary>
	public class ResourceEditorWidget : Gtk.VPaned
	{
		#region Child Widgets
		protected ResourceList resourceList = new ResourceList();
		protected Gtk.ScrolledWindow resourceScrollWindow = new Gtk.ScrolledWindow();
		protected Gtk.ScrolledWindow viewScrollWindow = new Gtk.ScrolledWindow();
		protected IResourceView currentView = null;
		#endregion
		
		#region Events
		/// <summary>Event is raised when the content of the widget has been changed</summary>
		public event EventHandler ContentChanged;
		#endregion
		
		#region Properties
		/// <summary>Gets or Sets the the list of resource items in the resource list.</summary>
		/// <value>An ArrayList containing the list of all the resource items.</value>
		public ArrayList ResourceItems
		{
			get { return this.resourceList.ResourceItems; }
			set { this.resourceList.ResourceItems = value; }
		}
		#endregion
		
		/// <summary>Initializes a new instance of the ResourceEditorView widget.</summary>
		public ResourceEditorWidget()
		{
			this.BorderWidth = 7;
			this.Position = 200;
			this.CanFocus = true;
			
			// Resource List Settings
			this.resourceList.Selection.Changed += new EventHandler(ResourceItem_Selected);
			this.resourceList.ContentChanged += new EventHandler(ResourceList_ContentChanged);
			
			// Add the Resource List Tree View
			resourceScrollWindow.ShadowType = Gtk.ShadowType.In;
			resourceScrollWindow.Add (this.resourceList);
			this.Add1(resourceScrollWindow);
			
			// Add the Resource View Window
			viewScrollWindow.ShadowType = Gtk.ShadowType.In;
			this.Add2(viewScrollWindow);
			
			this.Show();
		}
		
		/// <summary>Execute the event when the resource item has been selected</summary>
		/// <param name="sender">An object that contains the sender data.</param>
		/// <param name="e">An EventArgs object that contains the event data.</param>
		private void ResourceItem_Selected (object sender, EventArgs e)
		{
			Gtk.TreeIter iter;
			Gtk.TreeModel model;
			
			if (this.resourceList.Selection.GetSelected(out model, out iter))
			{
				// Get the resource item from the selection
				ResourceItem resourceItem = (ResourceItem) this.resourceList.Model.GetValue(iter, 3);
								
				// Add the IResourceView widget based on the type of the resource
				if (resourceItem.ResourceValue is string)
				{
					this.DisplayResourceView(new StringView(resourceItem));
				}
				else if (resourceItem.ResourceValue is bool)
				{
					this.DisplayResourceView(new BooleanView(resourceItem));
				}
				else
				{
					this.DisplayResourceView(null);
				}
			}
		}
		
		/// <summary>Execute the event when the content of the resource list has been changed</summary>
		/// <param name="sender">An object that contains the sender data.</param>
		/// <param name="e">An EventArgs object that contains the event data.</param>
		private void ResourceList_ContentChanged (object sender, EventArgs e)
		{
			if (this.ContentChanged != null)
			{
				this.ContentChanged(sender, e);
			}
		}
		
		/// <summary>Display the specified widget as the resource viewer.</summary>
		private void DisplayResourceView(Gtk.Widget viewer)
		{
			// Remove the current view widget
			if (this.viewScrollWindow.Children.Length > 0)
			{
				this.viewScrollWindow.Remove(this.viewScrollWindow.Children[0]);
			}
			
			// Add the viewer widget to the viewer scroll window
			if (viewer != null)
			{
				// Add the widget
				if (viewer is BooleanView)
				{
					this.viewScrollWindow.AddWithViewport(viewer);
				}
				else
				{
					this.viewScrollWindow.Add(viewer);
				}
				this.viewScrollWindow.ShowAll();
				
				// Set the widget values
				this.currentView = (IResourceView) viewer;
				this.currentView.WriteProtected = this.resourceList.WriteProtected;
				currentView.ResourceChanged += new ResourceChangedEventHandler(ViewResource_Changed);
			}
		}
		
		/// <summary>Set the value of the resource item whenever the value has been changed in the Resource Viewer widget.</summary>
		/// <param name="sender">An object that contains the sender data.</param>
		/// <param name="e">An ResourceEventArgs object that contains the event data.</param>
		private void ViewResource_Changed(object sender, ResourceEventArgs e)
		{
			this.resourceList.SetResourceValue(e.ResourceName, e.ResourceValue);
		}
		
		/// <summary>Load the resource file and populate the array list </summary>
		public void LoadFile(string filename)
		{
			ArrayList list = new ArrayList();
			
			FileInfo fileInfo = new FileInfo(filename);
			
			if (fileInfo.Exists)
			{
				switch (fileInfo.Extension.ToLower())
				{
					case ".resx":
						ResXResourceReader resXReader = new ResXResourceReader(filename);
						IDictionaryEnumerator item = resXReader.GetEnumerator();
						while (item.MoveNext())
						{
							ResourceItem resourceItem = new ResourceItem(item.Key.ToString(), item.Value);
							if (!list.Contains(resourceItem))
							{
								list.Add(resourceItem);
							}
						}
						resXReader.Close();
						break;
					case ".resources":
						//// new file will fail here - so we have to ignore exception(s)
						ResourceReader reader = null;
						try 
						{
							reader = new ResourceReader(filename);
							foreach (DictionaryEntry entry in reader) 
							{
								ResourceItem resourceItem = new ResourceItem(entry.Key.ToString(), entry.Value);
								if (!list.Contains(resourceItem))
								{
									list.Add(resourceItem);
								}
							}
						}
						catch 
						{
						}
						finally 
						{
							if (reader != null) 
							{
								reader.Close();
							}
						}
						break;
				}
			}
			
			// Set the Resource List and DataBind the widget
			this.resourceList.ResourceItems = list;
			this.resourceList.DataBind();
		}
		
		/// <summary>Save all the changes made to the a file. </summary>
		/// <param name="fileName">A string containing the name of the file.</param>
		public void SaveFile(string fileName)
		{
			FileInfo fileInfo = new FileInfo(fileName);
			
			//Debug.Assert(!writeProtected, "ICSharpCode.SharpDevelop.Gui.Edit.Resource.ResourceEdit.SaveFile(string filename) : trying to save a write protected file");
			switch (fileInfo.Extension.ToLower()) 
			{				
				// write XML resource
				case ".resx":
					ResXResourceWriter rxw    = new ResXResourceWriter(fileName);
					foreach (ResourceItem item in this.ResourceItems)
					{
						if (item.ResourceValue != null)
						{
							rxw.AddResource(item.Name, item.ResourceValue);
						}
					}
					rxw.Generate();
					rxw.Close();
				break;
				
				// write default resource
				default:
					ResourceWriter rw = new ResourceWriter(fileName);
					foreach (ResourceItem item in this.ResourceItems)
					{
						rw.AddResource(item.Name, item.ResourceValue);
					}
					rw.Generate();
					rw.Close();
				break;
			}
		}
	}
	
}
